#pragma once

#include "../../../Libs/headers.default.h"
#include "../../../Libs/headers.ipfe.h"
#include "../for_hiboost/headers.HiBoost.h"

#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <iomanip>
#include "common.h"
#include "AndNodeModel.h"
#include "OrNodeModel.h"
#include "LeafNodeModel.h"
#include "AndNode.h"
#include "OrNode.h"
#include "LeafNode.h"
#include "TreeStatistic.h"
#include "ImageEx.h"
#include "TMatrix.h"

using	namespace	std;

#ifndef M_PI
#define M_PI	3.1415926535897932384626
#endif

class CMyNodeInstance
{
public:
	double x, y, rot, scale;
	double Score, ShapeScore, AppearanceScore;
	double BaseAppearanceScore;
	bool fIsMissing;
};

class CMyTreeInstance
{
public:
	static double s_DetectionNMS_AOP_Thrshold;
public:
	double Score;
	CSimpleTypeArray<CMyNodeInstance> NodeInstanceList;
	CHiBoostNodeInstanceBoxSet NodeInstanceBoxSet;
	CRectBox<double> DetectionBox;

public:
	bool operator< (const CMyTreeInstance& AnotherInstance) const
	{
		return Score > AnotherInstance.Score;
	}
	bool operator== (const CMyTreeInstance& AnotherInstance) const
	{
		return Score == AnotherInstance.Score;
	}
public:
	static int DoDetectionNMS(
		CSimpleTypeArray<CMyTreeInstance>& DstReducedDetectionList,
		CSimpleTypeArray<CMyTreeInstance>& SrcOriginalDetectionList
		);
};

class CProposalTree
{
public:
	public:
		CProposalTree(void);
		~CProposalTree(void);

	public:
		ModelTreeType		model;
		CTreeStatistic		ParseStat;
		InstanceTreeType	template_tree;
		//int					root;

	public:
		int		SaveAndOrTreeModel(string strAndOrTreeFileName);
		int		ReadAndOrTreeModel(string strAndOrTreeFileName);
		int		PrepareModel();

		// common
		inline	double	OriDiff(double ori1, double ori2);

		// Learning parameters from ground-truth

		void LearnModelParamaters(
			const CHiBoostGroundTruthList& GT_List,
			string strPN_BaseParseLog,
			string strPN_TrainedModel,
			string strPN_LoadInstance,
			const CSimpleTypeArray<string>& List_strFN_SrcImage_Neg,
			const CSimpleTypeArray<string>& List_strSrcImageHashName_Neg);

		//int		ReadEntityFile(string strImageSetFileName, string strParseGroundPathName, vector<CHiBoostImageEntity>& ImageSet, string strFeaturePathName, int ParsedMode);
		int		LearnModelParamaters(
			string strPosTrainFileName, string strPosFeaturePathName, string strPosParseGroundPathName,
			string strNegTrainFileName, string strNegFeaturePathName, string strTrainParsePathName
			);

		double SetAndNodeThreshold(CSimpleTypeArray<InstanceTreeType>& GroundTruthInstList, double RootRecall);
		double SetAndNodeThreshold(CSimpleTypeArray<InstanceTreeType>& GroundTruthInstList);

		int		AddSearchCenterIndex(InstanceTreeType &tree, ArcModelType &Rule);

		int		RemakeTreeFromInst_NoEntity(InstanceTreeType &tree);
		int		MakeTreeFromInst(
			InstanceTreeType &tree, CHiBoostImageEntity &entity, NodeInstanceType &instance,
			bool fComputeAppearanceScore, bool fFindNearestSampledPixels);
		int		MakeTreeFromGround(InstanceTreeType &tree, CHiBoostImageEntity &entity, bool fComputeAppearanceScore);

		int		InitAverageModel(ModelTreeType &AveModel);
		int		MakeAverageModel(ModelTreeType &AveModel, int Count);

		// Parse

		void DoDetection(CSimpleTypeArray<CMyTreeInstance>& DstMyTreeInstanceList, CHiBoostImageEntity& SrcEntity);
		void DoDetection(CSimpleTypeArray<CMyTreeInstance>& DstMyTreeInstanceList, CHiBoostImageEntity& SrcEntity, double ScoreThreshold);

		bool MakeMyTreeInstance(CMyTreeInstance& DstMyTreeInstance, InstanceTreeType& TreeInstance, int InstanceIndex, CHiBoostImageEntity& Entity);
		void MakeMyNodeInstanceList(
			CSimpleTypeArray<CMyNodeInstance>& DstMyNodeInstanceList, bool fAppendMode, bool fUseFullInst,
			int NodeIndex, InstanceTreeType& TreeInstance, CHiBoostImageEntity& Entity);
		void MakeCanDetList(
			CSimpleTypeArray<CCandidateDetection>& DstCanDetList, bool fAppendMode, bool fUseFullInst,
			int NodeIndex, InstanceTreeType& TreeInstance, CHiBoostImageEntity& Entity);

		void	ParseGroundTruthList(
			CSimpleTypeArray<InstanceTreeType>& DstGroundTruthInstTreeList,
			const CHiBoostGroundTruthList& GT_List,
			bool fComputeAppearanceScore,
			string strPN_LoadInstance, string strPN_SaveInstance, string strPN_DrawInstance
			);
		void	ParseEntityGroundTruth(
			InstanceTreeType& DstInstTree,
			CHiBoostImageEntity& entity,
			bool fComputeAppearanceScore);
		void	ParseEntityCurrentLayer(
			InstanceTreeType& DstInstTree,
			CHiBoostImageEntity& entity,
			string strPN_ParseLog);
		void	ParseEntity(
			CSimpleTypeArray<CMyTreeInstance>& DstMyTreeInstanceList,
			CHiBoostImageEntity& entity,
			double ScoreThreshold,
			string strPN_ParseLog);

		void	RefreshMRFScore(InstanceTreeType& DstInstTree);

		// Make Standard Model

		void ReadStructFile(
			int								&LeafNodeAmount,
			vector<vector<vector<int>>>		&Hierarchy,
			vector<vector<int>>				&NodeIndex,
			string strFN_Struture);
		void CreateModelHierarchy(
			int								&LeafNodeAmount,
			vector<vector<vector<int>>>		&Hierarchy,
			vector<vector<int>>				&NodeIndex
			);
		void CreateNaiveModelFromLeafNodes(
			int								&LeafNodeAmount
		);

		void MakeStandardModel(
			string strFN_Struture,
			const CHiBoostGroundTruthList& GT_List,
			string strPN_SaveInstance, string strPN_DrawInstance);
		void MakeStandardLeafPositionModel(CSimpleTypeArray<InstanceTreeType>& InstTreeList, bool fFirstTime);
		void MakeStandardAndPositionModel(CSimpleTypeArray<InstanceTreeType>& InstTreeList);
		void MakeStandardAndPositionNode(CSimpleTypeArray<InstanceTreeType>& InstTreeList, int NodeIndex);
		void MakeStandardTripletNode(CSimpleTypeArray<InstanceTreeType>& InstTreeList, int NodeIndex);

		// Output
		int		PrintBoundary(NodeInstanceType &Instance, int ImageID, string strBoundaryFileName);
		int		DrawInstance(CHiBoostImageEntity &entity, NodeInstanceType &Instance, string strImageFileName);
		//int		DrawInstanceNode(CHiBoostImageEntity &entity, InstanceTreeType &TreeInstance, string strImageFileName, int NodeIndex);
};
